/**
 *  Concrete AdminRESTAdaptor implementation 
 *
 *  @author Scott Monahan
 *  @version $Id$
 *  
 *  File last changed on $Date:$ by $Author:$ in $Rev:$
 *
 */

package info637.pprc.adaptor;

import info637.pprc.ErrorCodes;
import info637.pprc.model.Property;
import info637.pprc.services.IPropertyService;
import info637.pprc.services.IPropertyService.AddPropertyResponse;
import info637.pprc.services.IPropertyService.LoginResponse;
import info637.pprc.services.IPropertyService.PropertyDetailResponse;
import info637.pprc.services.IPropertyService.PropertyListResponse;
import info637.pprc.services.IPropertyService.UpdatePropertyResponse;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component(value = "adminRESTAdaptor")
public class AdminRESTAdaptor extends AbstractRESTAdaptor
	implements IAdminRESTAdaptor {
	
	static Logger log = Logger.getLogger(AdminRESTAdaptor.class.getName());
	
	@Autowired
	private IPropertyService propertyService = null;
	
	@Override
	public Map<String, String> login(String requestId, String userName, String password) {
		
		java.util.Map<String, String> out = new java.util.HashMap<String, String>();
		
		out.put(APIConstants.requestId, requestId);
		
		List<ErrorCodes> validationErrors = validateLoginRequest(requestId, userName, password);
		
		if (validationErrors.size() == 0) {
		
			LoginResponse response = this.propertyService.login(userName, password);
			
			if (response.isError()) {
				
				out.put(APIConstants.errorCodes, this.errorCodesToString(response.getErrorCodes()));
				out.put(APIConstants.status, "1");
				
			} else {
				
				out.put(APIConstants.sessionId, response.getSessionId());
				out.put(APIConstants.status, "0");
			}
		
		} else {
			
			out.put(APIConstants.errorCodes, this.errorCodesToString(validationErrors));
			out.put(APIConstants.status, "1");
		}
		
		return out;
	}

	@Override
	public java.util.Map<String, Object> getPropertyListings(String requestId,
		String sessionId, String propertyName, String tenantName,
		String balance) {

		java.util.Map<String, Object> out = new java.util.HashMap<String, Object>();
		
		out.put(APIConstants.requestId, requestId);
		out.put(APIConstants.sessionId, sessionId);
		
		List<ErrorCodes> validationErrors = validateSessionRequest(requestId, sessionId);
		
		if (validationErrors.size() == 0 && (isStringValid(balance) && !validateNumeric(balance))) {
			
			validationErrors.add(ErrorCodes.INVALID_BALANCE);
		}
		
		if (validationErrors.size() == 0) {
		
			PropertyListResponse response 
				= this.propertyService.findByAdminFilterData(propertyName, tenantName, balance);
			
			if (response.isError()) {
				
				out.put(APIConstants.errorCodes, this.errorCodesToString(response.getErrorCodes()));
				out.put(APIConstants.status, "1");
				
			} else {
				
				List<Map<String, String>> outProperties = new ArrayList<Map<String, String>>();
				
				for (Property property : response.getPropertyList()) {
					
					java.util.Map<String, String> propertyMap = new java.util.HashMap<String, String>();
					
					propertyMap.put(APIConstants.propertyId, property.getId());
					propertyMap.put(APIConstants.propertyName, property.getPropertyName());
					propertyMap.put(APIConstants.tenantName, property.getTenantName());
					propertyMap.put(APIConstants.balance, property.getBalance());
					
					outProperties.add(propertyMap);
				}
				
				out.put(APIConstants.properties, outProperties);
				out.put(APIConstants.status, "0");
			}
		
		} else {
			
			out.put(APIConstants.errorCodes, this.errorCodesToString(validationErrors));
			out.put(APIConstants.status, "1");
		}
		
		return out;
	}

	@Override
	public Map<String, String> addProperty(String requestId, String sessionId,
		String propertyName, String address, String city, String state,
		String zip, String monthlyRent, String securityDeposit,
		String ownerName, String numOfBeds, String numOfBaths, String sqft,
		String appliances, String description, String contactInfo,
		String showOnline, String showInFlyer) {

		log.debug("Entering addProperty ...");
		
		java.util.Map<String, String> out = new java.util.HashMap<String, String>();
		
		out.put(APIConstants.requestId, requestId);
		out.put(APIConstants.sessionId, sessionId);
		
		List<ErrorCodes> validationErrors = validateAddRequest(
			requestId, sessionId, propertyName, address, city, state,
			zip, monthlyRent, securityDeposit, ownerName, numOfBeds, numOfBaths, sqft,
			appliances, description, contactInfo, showOnline, showInFlyer
		);
		
		log.debug("After validation ...");
		
		if (validationErrors.size() == 0) {
			
			log.debug("Validations are cleared ...");
		
			Property propertyToAdd = new Property(propertyName, address, city, state,
				zip, monthlyRent, securityDeposit, ownerName, numOfBeds, numOfBaths, sqft,
				appliances, description, contactInfo, showOnline, showInFlyer
			);
			
			log.debug("Created Property ...");
			
			AddPropertyResponse response = this.propertyService.addProperty(propertyToAdd);
			
			log.debug("Called service ...");
			
			if (response.isError()) {
				
				out.put(APIConstants.errorCodes, this.errorCodesToString(response.getErrorCodes()));
				out.put(APIConstants.status, "1");
				
			} else {
				
				log.debug("Add was reported as successful ...");
				
				out.put(APIConstants.status, "0");
			}
		
		} else {
			
			out.put(APIConstants.errorCodes, this.errorCodesToString(validationErrors));
			out.put(APIConstants.status, "1");
		}
		
		return out;
	}
	
	@Override
	public Map<String, String> getPropertyDetail(String requestId,
		String sessionId, String propertyId) {
		
		log.debug("Entering getPropertyDetail ...");
		
		java.util.Map<String, String> out = new java.util.HashMap<String, String>();
		
		out.put(APIConstants.requestId, requestId);
		out.put(APIConstants.sessionId, sessionId);
		
		List<ErrorCodes> validationErrors = validateGetPropertyDetail(requestId, sessionId, propertyId);
		
		log.debug("After validation ...");
		
		if (validationErrors.size() == 0) {
			
			log.debug("Validations are cleared ...");
		
			PropertyDetailResponse response = this.propertyService.getPropertyDetail(propertyId);
			
			log.debug("Called service ...");
			
			if (response.isError()) {
				
				out.put(APIConstants.errorCodes, this.errorCodesToString(response.getErrorCodes()));
				out.put(APIConstants.status, "1");
				
			} else {
				
				out.put(APIConstants.status, "0");
				
				out.put(APIConstants.requestId, requestId);
				out.put(APIConstants.propertyId, propertyId);
				out.put(APIConstants.propertyName, response.getProperty().getPropertyName());
				out.put(APIConstants.address, response.getProperty().getAddress());
				out.put(APIConstants.city, response.getProperty().getCity());
				out.put(APIConstants.state, response.getProperty().getState());
				out.put(APIConstants.zip, response.getProperty().getZip());
				out.put(APIConstants.monthlyRent, response.getProperty().getMonthlyRent());
				out.put(APIConstants.securityDeposit, response.getProperty().getSecurityDeposit());
				out.put(APIConstants.numOfBeds, response.getProperty().getNumOfBeds());
				out.put(APIConstants.numOfBaths, response.getProperty().getNumOfBaths());
				out.put(APIConstants.sqft, response.getProperty().getSqft());
				out.put(APIConstants.appliances, response.getProperty().getAppliances());
				out.put(APIConstants.description, response.getProperty().getDescription());
				out.put(APIConstants.contactInfo, response.getProperty().getContactInfo());
				out.put(APIConstants.showOnline, response.getProperty().getShowOnline());
				out.put(APIConstants.showInFlyer, response.getProperty().getShowInFlyer());
			}
		
		} else {
			
			out.put(APIConstants.errorCodes, this.errorCodesToString(validationErrors));
			out.put(APIConstants.status, "1");
		}
	
		return out;
	}

	@Override
	public Map<String, String> updateProperty(String requestId,
		String sessionId, String propertyId, String propertyName, 
		String monthlyRent, String securityDeposit, String ownerName, 
		String numOfBeds, String numOfBaths, String sqft, String appliances,
		String description, String contactInfo, String showOnline,
		String showInFlyer) {

		log.debug("Entering updateProperty ...");
		
		java.util.Map<String, String> out = new java.util.HashMap<String, String>();
		
		out.put(APIConstants.requestId, requestId);
		out.put(APIConstants.sessionId, sessionId);
		
		List<ErrorCodes> validationErrors = validateUpdateRequest(
			requestId, sessionId, propertyName, monthlyRent, securityDeposit, 
			ownerName, numOfBeds, numOfBaths, sqft,appliances, description, 
			contactInfo, showOnline, showInFlyer
		);
		
		log.debug("After validation ...");
		
		if (validationErrors.size() == 0) {
			
			log.debug("Validations are cleared ...");
		
			Property propertyToUpdate = new Property(propertyId, propertyName, monthlyRent, 
				securityDeposit, ownerName, numOfBeds, numOfBaths, sqft,
				appliances, description, contactInfo, showOnline, showInFlyer
			);
			
			UpdatePropertyResponse response = this.propertyService.updateProperty(propertyToUpdate);
			
			log.debug("Called service ...");
			
			if (response.isError()) {
				
				out.put(APIConstants.errorCodes, this.errorCodesToString(response.getErrorCodes()));
				out.put(APIConstants.status, "1");
				
			} else {
				
				log.debug("Update was reported as successful ...");
				
				out.put(APIConstants.status, "0");
			}
		
		} else {
			
			out.put(APIConstants.errorCodes, this.errorCodesToString(validationErrors));
			out.put(APIConstants.status, "1");
		}
		
		return out;
	}
	
	private List<ErrorCodes> validateLoginRequest(String requestId, String userName, String password) {
		
		List<ErrorCodes> errors = validateBaseRequest(requestId);
		
		if (!isStringValid(userName)) {
			
			errors.add(ErrorCodes.USER_NAME_REQUIRED);
		}
			
		if (!isStringValid(password)) {
			
			errors.add(ErrorCodes.PASSWORD_REQUIRED);
		}
		
		return errors;
	}
	
	private List<ErrorCodes> validateAddRequest(String requestId, String sessionId,
		String propertyName, String address, String city, String state,
		String zip, String monthlyRent, String securityDeposit,
		String ownerName, String numOfBeds, String numOfBaths, String sqft,
		String appliances, String description, String contactInfo,
		String showOnline, String showInFlyer) {
		
		List<ErrorCodes> errors = validateSessionRequest(requestId, sessionId);
		
		if (errors.size() == 0) {
		
			if (!isStringValid(address)) {
				
				errors.add(ErrorCodes.PROPERTY_ADDRESS_REQUIRED);
			}
			
			if (!isStringValid(city)) {
				
				errors.add(ErrorCodes.PROPERTY_CITY_REQUIRED);
			}
			
			if (!isStringValid(state)) {
				
				errors.add(ErrorCodes.PROPERTY_STATE_REQUIRED);
			}
			
			if (!isStringValid(zip)) {
				
				errors.add(ErrorCodes.PROPERTY_ZIP_REQUIRED);
			}
			
			if (!isStringValid(propertyName)) {
				
				errors.add(ErrorCodes.PROPERTY_NAME_REQUIRED);
			}
			
			if (!isStringValid(monthlyRent)) {
				
				errors.add(ErrorCodes.PROPERTY_MONTHLY_RENT_REQUIRED);
			}
			
			if (!isStringValid(contactInfo)) {
				
				errors.add(ErrorCodes.CONTACT_INFO_REQUIRED);
			}
		
			return validatePopertyData(errors, propertyName, monthlyRent, 
				securityDeposit, ownerName, numOfBeds, numOfBaths, sqft,
				appliances, description, contactInfo, showOnline, showInFlyer);
		
		} else {
			
			return errors;
		}
	}
	
	private List<ErrorCodes> validateUpdateRequest(String requestId, String sessionId,
		String propertyName, String monthlyRent, String securityDeposit,
		String ownerName, String numOfBeds, String numOfBaths, String sqft,
		String appliances, String description, String contactInfo,
		String showOnline, String showInFlyer) {
		
		List<ErrorCodes> errors = validateSessionRequest(requestId, sessionId);
		
		if (errors.size() == 0) {
			
			return validatePopertyData(errors, propertyName, monthlyRent, 
				securityDeposit, ownerName, numOfBeds, numOfBaths, sqft,
				appliances, description, contactInfo, showOnline, showInFlyer);
			
		} else {
			
			return errors;
		}
	}
	
	private List<ErrorCodes> validateGetPropertyDetail(String requestId, String sessionId,
		String propertyId) {
		
		List<ErrorCodes> errors = validateSessionRequest(requestId, sessionId);
		
		if (errors.size() == 0) {
			
			if (!isStringValid(propertyId)) {
				
				errors.add(ErrorCodes.PROPERTY_ID_REQUIRED);
			}
		}
		
		return errors;
	}
	
	private List<ErrorCodes> validatePopertyData(List<ErrorCodes> errors,
		String propertyName, String monthlyRent, String securityDeposit,
		String ownerName, String numOfBeds, String numOfBaths, String sqft,
		String appliances, String description, String contactInfo,
		String showOnline, String showInFlyer) {
		
		if (isStringValid(monthlyRent)) {
			
			if (!validateNumeric(monthlyRent)) {
				
				errors.add(ErrorCodes.INVALID_MONTHLY_RENT);
			}
		}
		
		if (!isStringValid(securityDeposit)) {
			
			securityDeposit = "0";
			
		} else {
			
			if (!validateNumeric(securityDeposit)) {
				
				errors.add(ErrorCodes.INVALID_SECURITY_DEPOSIT);
			}
		}

		if (isStringValid(numOfBeds) && !validateNumeric(numOfBeds)) {
			
			errors.add(ErrorCodes.INVALID_NUM_OF_BEDS);
		}

		if (isStringValid(numOfBaths) && !validateNumeric(numOfBaths)) {
			
			errors.add(ErrorCodes.INVALID_NUM_OF_BATHS);
		}
		
		if (isStringValid(sqft) && !validateNumeric(sqft)) {
			
			errors.add(ErrorCodes.INVALID_SQFT);
		}
		
		if (!isStringValid(showOnline)) {
			
			showOnline = "0";
			
		} else {
			
			if (!validateNumeric(showOnline)) {
				
				errors.add(ErrorCodes.INVALID_SHOW_ONLINE_FLAG);
			}
		}
		
		if (!isStringValid(showInFlyer)) {
			
			showInFlyer = "0";
			
		} else {
			
			if (!validateNumeric(showInFlyer)) {
				
				errors.add(ErrorCodes.INVALID_SHOW_IN_FLYER_FLAG);
			}
		}
		
		return errors;
	}
}